#pragma once

#include <QString>
#include <QIcon>
#include <QUuid>
#include <QDateTime>
#include <QFile>
#include <QDebug>
#include <QFileInfo>

#include "base.qpb.h"

namespace model {

//////////////////////////////////////
/// 工具函数
//////////////////////////////////////

// 生成 uuid
static inline QString makeId() {
    return "M" + QUuid::createUuid().toString().sliced(25, 12);
}

// 获取时间戳
static inline qint64 getTime() {
    return QDateTime::currentSecsSinceEpoch();
}

// 将时间戳转换成格式化时间
static inline QString formatTime(qint64 timestamp) {
    QDateTime time = QDateTime::fromSecsSinceEpoch(timestamp);
    return time.toString("MM/dd hh:mm");
}

// 将 QByteArray 转换成 Icon
static inline QIcon makeIcon(const QByteArray& data) {
    QPixmap pixmap;
    pixmap.loadFromData(data);
    return QIcon(pixmap);
}

// 文件操作
// 从文件中读取 QByteArray
static inline QByteArray readByteArrayFromFile(const QString& path) {
    QFile file(path);
    bool ok = file.open(QFile::ReadOnly);
    if(!ok) {
        qDebug() << "打开文件失败!";
        return QByteArray();
    }
    return file.readAll();
}

// 将 QByteArray 写入文件
static inline void writeByteArrayToFile(const QString& path, const QByteArray& data) {
    QFile file(path);
    bool ok = file.open(QFile::WriteOnly);
    if(!ok) {
        qDebug() << "打开文件失败!";
        return;
    }
    file.write(data);
    file.flush();
}

// 获取文件名
static inline QString getFileName(const QString& path) {
    QFileInfo info(path);
    return info.fileName();
}

// 日志打印
#define TAG QString("[%1:%2]").arg(model::getFileName(__FILE__), QString::number(__LINE__))
#define LOG() qDebug().noquote() << TAG

//////////////////////////////////////
/// 用户信息
//////////////////////////////////////
class UserInfo {
public:
    QString userId = "";         // 用户编号
    QString nickname = "";       // 用户昵称
    QString phone = "";          // 手机号
    QString description = "";    // 用户签名
    QIcon avatar;                // 用户头像

    // 从 protobuf 中的 UserInfo 类加载当前项目中的 UserInfo 类
    void load(const bite_im::UserInfo& userInfo) {
        this->userId = userInfo.userId();
        this->nickname = userInfo.nickname();
        this->phone = userInfo.phone();
        this->description = userInfo.description();
        if(userInfo.avatar().isEmpty()) {
            avatar = QIcon(":/resource/image/default_avatar.png");
        } else {
            this->avatar = makeIcon(userInfo.avatar());
        }
    }
};

//////////////////////////////////////
/// 消息类型
//////////////////////////////////////
enum MessageType {
    TEXT_TYPE,      // 文本消息
    IMAGE_TYPE,     // 图片消息
    FILE_TYPE,      // 文件消息
    SPEECH_TYPE     // 语音消息
};

//////////////////////////////////////
/// 消息定义
//////////////////////////////////////

class Message {
public:
    QString msgId = "";          // 消息编号
    QString sessionId = "";      // 消息所属的会话编号
    QString time = "";           // 时间
    MessageType type = TEXT_TYPE;// 消息类型
    UserInfo sender;             // 消息的发送者
    QByteArray content;          // 消息正文,可能是字符串,也可能是图片/文件/语音等二进制数据
    QString fileId = "";         // 图片/文件/语音消息可能体积很大,先拿到它们的id,再进一步处理
    QString fileName = "";       // 只有文件消息有效

    static Message makeMessage(MessageType type, const QString& sessionId,
                               const UserInfo& sender, const QByteArray& content,
                               const QString& extra) {
        if(type == TEXT_TYPE) {
            return makeTextMessage(sessionId, sender, content);
        } else if(type == IMAGE_TYPE) {
            return makeImageMessage(sessionId, sender, content);
        } else if(type == FILE_TYPE) {
            return makeFileMessage(sessionId, sender, content, extra);
        } else if(type == SPEECH_TYPE) {
            return makeSpeechMessage(sessionId, sender, content);
        } else {
            return Message();
        }
    }

    // 从 protobuf 中的 MessageInfo 类加载当前项目中的 Message 类
    void load(const bite_im::MessageInfo& msgInfo) {
        this->msgId = msgInfo.messageId();
        this->sessionId = msgInfo.chatSessionId();
        this->time = formatTime(msgInfo.timestamp());
        this->sender.load(msgInfo.sender());
        auto type = msgInfo.message().messageType();
        if(type == bite_im::MessageTypeGadget::MessageType::STRING) {
            this->type = TEXT_TYPE;
            this->content = msgInfo.message().stringMessage().content().toUtf8();
        } else if(type == bite_im::MessageTypeGadget::MessageType::IMAGE) {
            this->type = IMAGE_TYPE;
            if(msgInfo.message().imageMessage().hasFileId()) {
                this->fileId = msgInfo.message().imageMessage().fileId();
            }
            if(msgInfo.message().imageMessage().hasImageContent()) {
                this->content = msgInfo.message().imageMessage().imageContent();
            }
        } else if(type == bite_im::MessageTypeGadget::MessageType::FILE) {
            this->type = FILE_TYPE;
            if(msgInfo.message().fileMessage().hasFileId()) {
                this->fileId = msgInfo.message().fileMessage().fileId();
            }
            if(msgInfo.message().fileMessage().hasFileName()) {
                this->fileName = msgInfo.message().fileMessage().fileName();
            }
            if(msgInfo.message().fileMessage().hasFileContents()) {
                this->content = msgInfo.message().fileMessage().fileContents();
            }
        } else if(type == bite_im::MessageTypeGadget::MessageType::SPEECH) {
            this->type = SPEECH_TYPE;
            if(msgInfo.message().speechMessage().hasFileId()) {
                this->fileId = msgInfo.message().speechMessage().fileId();
            }
            if(msgInfo.message().speechMessage().hasFileContents()) {
                this->content = msgInfo.message().speechMessage().fileContents();
            }
        } else {
            LOG() << "未知的文件类型";
        }
    }

private:
    static Message makeTextMessage(const QString& sessionId, const UserInfo& sender,
                                   const QByteArray& content) {
        Message msg;
        msg.msgId = makeId();
        msg.sessionId = sessionId;
        msg.time = formatTime(getTime());
        msg.type = TEXT_TYPE;
        msg.sender = sender;
        msg.content = content;
        // fileId 和 fileName 都无效
        msg.fileId = "";
        msg.fileName = "";
        return msg;
    }

    static Message makeImageMessage(const QString& sessionId, const UserInfo& sender,
                                    const QByteArray& content) {
        Message msg;
        msg.msgId = makeId();
        msg.sessionId = sessionId;
        msg.time = formatTime(getTime());
        msg.type = IMAGE_TYPE;
        msg.sender = sender;
        msg.content = content;
        // fileID 有效,fileName 无效
        msg.fileId = "";
        msg.fileName = "";
        return msg;
    }

    static Message makeFileMessage(const QString& sessionId, const UserInfo& sender,
                                   const QByteArray& content, const QString& extra) {
        Message msg;
        msg.msgId = makeId();
        msg.sessionId = sessionId;
        msg.time = formatTime(getTime());
        msg.type = IMAGE_TYPE;
        msg.sender = sender;
        msg.content = content;
        // fileID 有效,fileName 无效
        msg.fileId = "";
        msg.fileName = extra;
        return msg;
    }

    static Message makeSpeechMessage(const QString& sessionId, const UserInfo& sender,
                                     const QByteArray& content) {
        Message msg;
        msg.msgId = makeId();
        msg.sessionId = sessionId;
        msg.time = formatTime(getTime());
        msg.type = IMAGE_TYPE;
        msg.sender = sender;
        msg.content = content;
        // fileID 有效,fileName 无效
        msg.fileId = "";
        msg.fileName = "";
        return msg;
    }
};

//////////////////////////////////////
/// 会话信息
//////////////////////////////////////
class ChatSessionInfo {
public:
    QString sessionId = "";          // 会话编号
    QString sessionName = "";        // 会话名称,单聊:对方昵称 群聊:群聊名称
    QIcon avatar;                    // 会话头像,单聊:对方头像 群聊:群聊头像
    Message lastMessage;             // 最新消息
    QString userId = "";             // 会话中用户id,单聊:对方id 群聊:默认为"",后续拿到所有用户id

    // 从 protobuf 中的 ChatSeesionInfo 类加载当前项目中的 ChatSesionInfo 类
    void load(const bite_im::ChatSessionInfo& chatSessionInfo) {
        this->sessionId = chatSessionInfo.chatSessionId();
        this->sessionName = chatSessionInfo.chatSessionName();
        if(chatSessionInfo.hasSingleChatFriendId()) {
            this->userId = chatSessionInfo.singleChatFriendId();
        }
        if(chatSessionInfo.hasPrevMessage()) {
            this->lastMessage.load(chatSessionInfo.prevMessage());
        }
        if(chatSessionInfo.hasAvatar() && !chatSessionInfo.avatar().isEmpty()) {
            // 设置了头像并且头像不为空,就用设置好的头像
            this->avatar = makeIcon(chatSessionInfo.avatar());
        } else {
            if(userId != "") {
                // 单聊
                this->avatar = QIcon(":/resource/image/default_avatar.png");
            } else {
                // 群聊
                this->avatar = QIcon(":/resource/image/group_default_avatar.png");
            }
        }
    }
};

} // end model
